package engine.render.buffer;

import engine.render.GLManager;
import engine.render.type.Tri;
import java.util.Arrays;
import java.util.Comparator;

public class TriBuffer 
{
    
    private static final int POLYGON_LIMIT = 500;
    
    public Tri[] tris;
    
    private int nTrisSent;
    public int nTrisSent() 
    {
        return nTrisSent;
    }
    
    private int nTrisRendered;
    public int nTrisRendered() 
    {
        return nTrisRendered;
    }
    
    public TriBuffer() 
    {
        tris = new Tri[POLYGON_LIMIT];
        nTrisSent = 0;
        nTrisRendered = 0;
    }
    
    public float[] asFloatArray()
    {
        nTrisRendered = 0;
        int nCompNorm = 9; // All per-triangle
        int nCompTexCoord = 6;
        int nCompVert = 9;
        int nCompPerTri = (nCompNorm + nCompTexCoord + nCompVert);
        float[] result = new float[nTrisSent * nCompPerTri];
        int j;
        for (int i = 0; i < nTrisSent; i++)
        {
            j = 0;
            if (tris[i] != null)
            {
                nTrisRendered++;
                result[i * nCompPerTri + j++] = tris[i].verts[0].x;
                result[i * nCompPerTri + j++] = tris[i].verts[0].y;
                result[i * nCompPerTri + j++] = tris[i].verts[0].z;
                result[i * nCompPerTri + j++] = tris[i].norm.x;
                result[i * nCompPerTri + j++] = tris[i].norm.y;
                result[i * nCompPerTri + j++] = tris[i].norm.z;
                result[i * nCompPerTri + j++] = tris[i].texs[0].x;
                result[i * nCompPerTri + j++] = tris[i].texs[0].y;
                
                result[i * nCompPerTri + j++] = tris[i].verts[1].x;
                result[i * nCompPerTri + j++] = tris[i].verts[1].y;
                result[i * nCompPerTri + j++] = tris[i].verts[1].z;
                result[i * nCompPerTri + j++] = tris[i].norm.x;
                result[i * nCompPerTri + j++] = tris[i].norm.y;
                result[i * nCompPerTri + j++] = tris[i].norm.z;
                result[i * nCompPerTri + j++] = tris[i].texs[1].x;
                result[i * nCompPerTri + j++] = tris[i].texs[1].y;
                
                result[i * nCompPerTri + j++] = tris[i].verts[2].x;
                result[i * nCompPerTri + j++] = tris[i].verts[2].y;
                result[i * nCompPerTri + j++] = tris[i].verts[2].z;
                result[i * nCompPerTri + j++] = tris[i].norm.x;
                result[i * nCompPerTri + j++] = tris[i].norm.y;
                result[i * nCompPerTri + j++] = tris[i].norm.z;
                result[i * nCompPerTri + j++] = tris[i].texs[2].x;
                result[i * nCompPerTri + j++] = tris[i].texs[2].y;
            }
        }
        return result;
    }
    
    //<editor-fold defaultstate="collapsed" desc="Get Float[] Representation Methods">
    public float[] getNormals()
    {
        nTrisRendered = 0;
        int nComponentsPerTri = 9;
        float[] norms = new float[nTrisSent * nComponentsPerTri];
        int j;
        for (int i = 0; i < nTrisSent; i++)
        {
            j = 0;
            if (tris[i] != null)
            {
                nTrisRendered++;
                norms[i * nComponentsPerTri + j++] = tris[i].norm.x;
                norms[i * nComponentsPerTri + j++] = tris[i].norm.y;
                norms[i * nComponentsPerTri + j++] = tris[i].norm.z;
                norms[i * nComponentsPerTri + j++] = tris[i].norm.x;
                norms[i * nComponentsPerTri + j++] = tris[i].norm.y;
                norms[i * nComponentsPerTri + j++] = tris[i].norm.z;
                norms[i * nComponentsPerTri + j++] = tris[i].norm.x;
                norms[i * nComponentsPerTri + j++] = tris[i].norm.y;
                norms[i * nComponentsPerTri + j++] = tris[i].norm.z;
            }
        }
        return norms;
    }
    
    public float[] getTexCoords()
    {
        int nComponentsPerTri = 6;
        float[] texCoords = new float[nTrisSent * nComponentsPerTri];
        int j;
        for (int i = 0; i < nTrisSent; i++)
        {
            j = 0;
            if (tris[i] != null)
            {
                texCoords[i * nComponentsPerTri + j++] = tris[i].texs[0].x;
                texCoords[i * nComponentsPerTri + j++] = tris[i].texs[0].y;
                texCoords[i * nComponentsPerTri + j++] = tris[i].texs[1].x;
                texCoords[i * nComponentsPerTri + j++] = tris[i].texs[1].y;
                texCoords[i * nComponentsPerTri + j++] = tris[i].texs[2].x;
                texCoords[i * nComponentsPerTri + j++] = tris[i].texs[2].y;
            }
        }
        return texCoords;
    }
    
    public float[] getVertices()
    {
        int nComponentsPerTri = 9;
        float[] vertices = new float[nTrisSent * nComponentsPerTri];
        int j;
        for (int i = 0; i < nTrisSent; i++)
        {
            j = 0;
            if (tris[i] != null)
            {
                vertices[i * nComponentsPerTri + j++] = tris[i].verts[0].x;
                vertices[i * nComponentsPerTri + j++] = tris[i].verts[0].y;
                vertices[i * nComponentsPerTri + j++] = tris[i].verts[0].z;
                vertices[i * nComponentsPerTri + j++] = tris[i].verts[1].x;
                vertices[i * nComponentsPerTri + j++] = tris[i].verts[1].y;
                vertices[i * nComponentsPerTri + j++] = tris[i].verts[1].z;
                vertices[i * nComponentsPerTri + j++] = tris[i].verts[2].x;
                vertices[i * nComponentsPerTri + j++] = tris[i].verts[2].y;
                vertices[i * nComponentsPerTri + j++] = tris[i].verts[2].z;
            }
        }
        return vertices;
    }
    //</editor-fold>
    
    //<editor-fold defaultstate="collapsed" desc="Add">
    public void triangle(Tri tri) 
    {
        tris[nTrisSent++] = tri;
    }
    
    public void triangles(Tri[] tris) 
    {
        for (int i = 0; i < tris.length; i++) 
        {
            triangle(tris[i]);
        }
    }
    //</editor-fold>
    
    //<editor-fold defaultstate="collapsed" desc="Sort">
    private Comparator comparator = new Comparator() 
    {
        public int compare(Object o1, Object o2) 
        {
            return compareTris(
                (Tri) o1,
                (Tri) o2
            );
        }
        
        private int compareTris(Tri t0, Tri t1) 
        {
            if (t0 == null || t1 == null) 
            {
                return 0;
            }
            else if (t0.tex.texIndex == t1.tex.texIndex) 
            {
                return 0;
            }
            else if (t0.tex.texIndex < t1.tex.texIndex) 
            {
                return -1;
            }
            else 
            {
                return 1;
            }
        }
    };
    
    public void sort() 
    {
        Arrays.sort(tris, comparator);
    }
    //</editor-fold>
    
    //<editor-fold defaultstate="collapsed" desc="Render">
    public void renderTris(GLManager glManager) 
    {
        nTrisRendered = 0;
        for (int i = 0; i < nTrisSent; i++) 
        {
            if (tris[i] != null) 
            {
                tris[i].render(glManager);
                nTrisRendered++;
            }
        }
    }
    //</editor-fold>
    
    //<editor-fold defaultstate="collapsed" desc="Clear">
    public void clearTris() 
    {
        for (int i = 0; i < nTrisSent; i++) 
        {
            tris[i] = null;
        }
        nTrisSent = 0;
    }
    //</editor-fold>
    
}
